// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.ui.process.editors;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dengues.core.DenguesCorePlugin;
import org.dengues.core.IDesignerCoreService;
import org.dengues.core.components.ENodeParameterName;
import org.dengues.core.components.NodePropertyParameter;
import org.dengues.core.external.AbstractCompNodeExt;
import org.dengues.core.metadata.MetadataColumn;
import org.dengues.core.metadata.MetadataTable;
import org.dengues.core.prefs.IDenguesPrefsConstant;
import org.dengues.core.process.CompElement;
import org.dengues.core.process.EConnectionType;
import org.dengues.core.process.ICompBlockExit;
import org.dengues.core.process.ICompConnection;
import org.dengues.core.process.IGefNode;
import org.dengues.core.property.EParameterFieldCategory;
import org.dengues.core.resource.WarehouseResourceFactory;
import org.dengues.core.runprocess.IJavaETLProcessor;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.designer.ui.process.models.CompBlock;
import org.dengues.designer.ui.process.models.CompBlockExit;
import org.dengues.designer.ui.process.models.CompConnection;
import org.dengues.designer.ui.process.models.CompNode;
import org.dengues.designer.ui.process.models.CompNote;
import org.dengues.designer.ui.process.models.CompProcess;
import org.dengues.model.warehouse.BlockExitType;
import org.dengues.model.warehouse.BlockType;
import org.dengues.model.warehouse.ColumnType;
import org.dengues.model.warehouse.ConnectionType;
import org.dengues.model.warehouse.ElementParameterType;
import org.dengues.model.warehouse.ElementValueType;
import org.dengues.model.warehouse.MetadataType;
import org.dengues.model.warehouse.NodeType;
import org.dengues.model.warehouse.NoteType;
import org.dengues.model.warehouse.ProcessType;
import org.dengues.model.warehouse.WarehouseFactory;
import org.dengues.ui.DenguesUiPlugin;
import org.dengues.ui.editors.AbstractEditorInput;
import org.dengues.ui.editors.AbstractGenericGEFEditor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.preference.PreferenceConverter;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf Qiang.Zhang.Adolf@gmail.com 2008-1-24 qiang.zhang $
 * 
 */
public class ProcessEditorInput extends AbstractEditorInput {

    protected CompProcess process;

    protected ProcessType processType;

    private final boolean isBlock;

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessEditorInput constructor comment.
     * 
     * @param file
     * @param objName
     * @param name
     * @param path
     */
    public ProcessEditorInput(IFile file, String objName, ENodeCategoryName name, IPath path) {
        super(file, objName, name, path);
        isBlock = ENodeCategoryName.BLOCKS == name;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessEditorInput constructor comment.
     * 
     * @param file
     * @param objName
     * @param name
     */
    public ProcessEditorInput(IFile file, String objName, ENodeCategoryName name) {
        super(file, objName, name);
        isBlock = ENodeCategoryName.BLOCKS == name;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessEditorInput constructor comment.
     */
    public ProcessEditorInput(String objName, ENodeCategoryName name, IPath path, String label) {
        super(objName, name, path, label);
        this.process = null;
        this.processType = null;
        // setEMFStorage(processType);
        isBlock = ENodeCategoryName.BLOCKS == name;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ProcessEditorInput constructor comment.
     * 
     * @param processType
     * @param path
     */
    public ProcessEditorInput(ProcessType processType, IPath path) {
        super(processType.getName(), ENodeCategoryName.PROCESS, path, processType.getUuid());
        this.processType = processType;
        // setEMFStorage(processType);
        isBlock = false;
    }

    /**
     * Getter for processType.
     * 
     * @return the processType
     */
    public ProcessType getProcessType() {
        if (this.processType == null) {
            this.processType = (ProcessType) getEMFStorage();
        }
        return this.processType;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "loadProcess".
     * 
     * @return
     */
    public CompProcess loadProcess() {
        CompProcess process = new CompProcess();
        process.setName(getProcessType().getName());
        process.setPurpose(getProcessType().getComment());
        process.setBlock(isBlock);
        List<NodeType> nodes = getProcessType().getNode();
        for (NodeType type : nodes) {
            CompNode compNode = new CompNode(getComponent(type.getCompName()));
            compNode.setLocation(new Point(type.getPosX(), type.getPosY()));
            Dimension defaultSize = AbstractGenericGEFEditor.getDefaultSize();
            if (type.getSizeW() > 0 && type.getSizeH() > 0) {
                defaultSize = new Dimension(type.getSizeW(), type.getSizeH());
            }
            compNode.setSize(defaultSize);
            List<ElementParameterType> elementParameters = type.getElementParameter();
            for (ElementParameterType elementParamType : elementParameters) {
                NodePropertyParameter elementParameter = compNode.getElementParameter(elementParamType.getName());
                EParameterFieldCategory fieldCategory = elementParameter.getFieldCategory();
                String value = elementParamType.getValue();
                if (elementParameter != null) {
                    if (EParameterFieldCategory.TABLE.compareTo(fieldCategory) == 0) {
                        List<Map<String, Object>> mapps = (List<Map<String, Object>>) elementParameter.getValue();
                        EList<ElementValueType> paramValues = elementParamType.getParamValues();
                        String[] itemNames = elementParameter.getItemNames();
                        for (int j = 0; j < paramValues.size(); j += itemNames.length) {
                            Map<String, Object> map = new HashMap<String, Object>();
                            for (int j2 = 0; j2 < itemNames.length; j2++) {
                                ElementValueType evt = paramValues.get(j + j2);
                                String field = evt.getField();
                                EParameterFieldCategory catField = EParameterFieldCategory.getCategoryFromField(field);
                                switch (catField) {
                                case CHECK:
                                    map.put(evt.getRefParam(), new Boolean(evt.getValue()));
                                    break;
                                default:
                                    map.put(evt.getRefParam(), evt.getValue());
                                    break;
                                }
                            }
                            mapps.add(map);
                        }
                    } else {
                        elementParameter.setValue(value);
                    }
                }
            }
            compNode.getNodeLabel().setNodeLabel(
                    compNode.getElementParameter(ENodeParameterName.UNIQUE_NAME.getName()).getValue().toString());
            compNode.setCompProcess(process);
            process.addCompNode(compNode);
            process.addCompNodeLabel(compNode.getNodeLabel());
            process.addCompNodeStatus(compNode.getNodeStatus());
            compNode.setStringData(type.getStringData());
            EList metadata = type.getMetadata();
            if (metadata.size() > 0) {
                MetadataType metadataType = (MetadataType) metadata.get(0);
                MetadataTable table = new MetadataTable();
                table.setTableName(metadataType.getName());
                List<ColumnType> cs = metadataType.getColumn();
                List<MetadataColumn> cols = new ArrayList<MetadataColumn>();
                for (ColumnType columnType : cs) {
                    MetadataColumn column = new MetadataColumn();
                    column.setColumnName(columnType.getName());
                    column.setType(columnType.getType());
                    cols.add(column);
                }
                table.setColumns(cols);
                compNode.getMetadataList().clear();
                compNode.getMetadataList().add(table);
            }
        }
        List<NoteType> notes = getProcessType().getNote();
        for (NoteType type : notes) {
            CompNote compNote = new CompNote();
            compNote.setOpaque(type.isOpaque());
            compNote.setLocation(new Point(type.getPosX(), type.getPosY()));
            compNote.setSize(new Dimension(type.getSizeW(), type.getSizeH()));
            compNote.setText(type.getText());
            process.addCompNote(compNote);
            compNote.setCompProcess(process);
        }
        List<BlockType> blocks = getProcessType().getBlock();
        for (BlockType type : blocks) {
            CompBlock compNote = new CompBlock(type.getUuid(), type.getName());
            compNote.setLocation(new Point(type.getPosX(), type.getPosY()));
            compNote.setSize(new Dimension(type.getSizeW(), type.getSizeH()));
            compNote.setColor(PreferenceConverter.getColor(DenguesUiPlugin.getDefault().getPreferenceStore(),
                    IDenguesPrefsConstant.DESIGNER_COLOR_BLOCK));
            process.addCompBlock(compNote);
            compNote.setCompProcess(process);
        }

        EList<BlockExitType> exits = getProcessType().getExits();
        for (BlockExitType type : exits) {
            CompBlockExit compNote = new CompBlockExit(type.getUuid(), type.getName());
            compNote.setLocation(new Point(type.getPosX(), type.getPosY()));
            compNote.setSize(new Dimension(type.getSizeW(), type.getSizeH()));
            compNote.setName(type.getName());
            compNote.setColor(PreferenceConverter.getColor(DenguesUiPlugin.getDefault().getPreferenceStore(),
                    IDenguesPrefsConstant.DESIGNER_COLOR_BLOCK));
            compNote.setEnter(type.isEnter());
            compNote.setCompProcess(process);
            process.addCompBlockExit(compNote);
        }

        List<ConnectionType> connections = getProcessType().getConnection();
        for (ConnectionType connType : connections) {
            String source = connType.getSource();
            IGefNode sourceNode = getCompNode(process, source);
            IGefNode targetNode = getCompNode(process, connType.getTarget());
            if (sourceNode != null && targetNode != null) {
                CompConnection compConnection = new CompConnection(sourceNode, targetNode, EConnectionType.getType(connType
                        .getType()), connType.getName());
                process.addCompConnectionLabel(compConnection.getConnectionLabel());
                process.addCompConnectionTrac(compConnection.getConnectionTrac());
            }
        }
        return process;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getCompNode".
     * 
     * @param process
     * @param unName
     * @return
     */
    private IGefNode getCompNode(CompProcess process, String unName) {
        for (CompElement node : process.getElements()) {
            if (node.getUniqueName().equals(unName)) {
                return node;
            }
        }
        return null;
    }

    /**
     * Getter for process.
     * 
     * @return the process
     */
    public CompProcess getProcess() {
        if (process == null) {
            process = loadProcess();
        }
        return this.process;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "saveEMF".
     * 
     * @param process
     */
    public void saveEMF(CompProcess process) {
        List<CompNode> compNodes = process.getCompNodes();
        getProcessType().setIsblock(process.isBlock());
        getProcessType().getNode().clear();
        getProcessType().getConnection().clear();
        for (CompNode node : compNodes) {
            NodeType nodeType = WarehouseFactory.eINSTANCE.createNodeType();
            nodeType.setCompName(node.getComponent().getName());
            nodeType.setPosX(node.getLocation().x);
            nodeType.setPosY(node.getLocation().y);
            nodeType.setSizeH(node.getSize().height);
            nodeType.setSizeW(node.getSize().width);
            AbstractCompNodeExt eNode = node.getExternalNode(false);
            if (eNode != null) {
                String sData = eNode.getStringData();
                nodeType.setStringData(sData);
            }
            saveElementParameters(nodeType, node);
            saveConnections(node);
            saveMetadata(nodeType, node);
            getProcessType().getNode().add(nodeType);
        }

        List<CompNote> compNotes = process.getCompNotes();
        getProcessType().getNote().clear();
        for (CompNote node : compNotes) {
            NoteType nodeType = WarehouseFactory.eINSTANCE.createNoteType();
            nodeType.setPosX(node.getLocation().x);
            nodeType.setPosY(node.getLocation().y);
            nodeType.setOpaque(node.isOpaque());
            nodeType.setText(node.getText());
            nodeType.setSizeH(node.getSize().height);
            nodeType.setSizeW(node.getSize().width);
            getProcessType().getNote().add(nodeType);
        }

        List<CompBlock> compBlocks = process.getCompBlocks();
        getProcessType().getBlock().clear();
        for (CompBlock node : compBlocks) {
            BlockType nodeType = WarehouseFactory.eINSTANCE.createBlockType();
            nodeType.setPosX(node.getLocation().x);
            nodeType.setPosY(node.getLocation().y);
            nodeType.setSizeH(node.getSize().height);
            nodeType.setSizeW(node.getSize().width);
            nodeType.setName(node.getCompName());
            nodeType.setUuid(node.getBlockId());
            saveConnections(node);
            getProcessType().getBlock().add(nodeType);
        }

        List<ICompBlockExit> exits = process.getExits();
        getProcessType().getExits().clear();
        for (ICompBlockExit nodeExit : exits) {
            CompBlockExit node = (CompBlockExit) nodeExit;
            BlockExitType nodeType = WarehouseFactory.eINSTANCE.createBlockExitType();
            nodeType.setPosX(node.getLocation().x);
            nodeType.setPosY(node.getLocation().y);
            nodeType.setSizeH(node.getSize().height);
            nodeType.setSizeW(node.getSize().width);
            nodeType.setName(node.getCompName());
            nodeType.setUuid(node.getBlockId());
            nodeType.setEnter(node.isEnter());
            saveConnections(node);
            getProcessType().getExits().add(nodeType);
        }
        WarehouseResourceFactory.saveStorage(getProcessType());
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "saveMetadata".
     * 
     * @param nodeType
     * 
     * @param node
     */
    private void saveMetadata(NodeType nodeType, CompNode node) {
        List<MetadataTable> metadata = node.getMetadataList();
        for (MetadataTable metadataTable : metadata) {
            MetadataType metadataType = WarehouseFactory.eINSTANCE.createMetadataType();
            metadataType.setName(metadataTable.getTableName());
            List<MetadataColumn> columns = metadataTable.getColumns();
            for (MetadataColumn metadataColumn : columns) {
                ColumnType columnType = WarehouseFactory.eINSTANCE.createColumnType();
                columnType.setName(metadataColumn.getColumnName());
                columnType.setType(metadataColumn.getType());
                metadataType.getColumn().add(columnType);
            }
            nodeType.getMetadata().add(metadataType);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "saveConnections".
     * 
     * @param nodeType
     * @param node
     */
    private void saveConnections(IGefNode node) {
        List<? extends ICompConnection> ins = node.getIncomingConnections();
        for (ICompConnection conn : ins) {
            ConnectionType connType = WarehouseFactory.eINSTANCE.createConnectionType();
            connType.setSource(conn.getSource().getUniqueName());
            connType.setTarget(node.getUniqueName());
            connType.setName(conn.getName());
            connType.setType(conn.getType().toString());
            getProcessType().getConnection().add(connType);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "saveElementParameters".
     * 
     * @param nodeType
     * @param node
     */
    private void saveElementParameters(NodeType nodeType, CompNode node) {
        List<NodePropertyParameter> elementParameters = node.getElementParameters();
        nodeType.getElementParameter().clear();
        for (NodePropertyParameter nodePropertyParameter : elementParameters) {
            ElementParameterType parameterType = WarehouseFactory.eINSTANCE.createElementParameterType();
            parameterType.setField(nodePropertyParameter.getField());
            parameterType.setName(nodePropertyParameter.getName());
            Object value = nodePropertyParameter.getValue();
            Object[] itemValues = nodePropertyParameter.getItemValues();
            if (EParameterFieldCategory.TABLE.compareTo(nodePropertyParameter.getFieldCategory()) == 0) {
                List<Map<String, Object>> mappings = (List<Map<String, Object>>) value;
                for (Map<String, Object> object : mappings) {
                    for (Object obj1 : itemValues) {
                        NodePropertyParameter parameter = (NodePropertyParameter) obj1;
                        String key1 = parameter.getName();
                        ElementValueType elemValueType = WarehouseFactory.eINSTANCE.createElementValueType();
                        elemValueType.setRefParam(key1);
                        Object value2 = object.get(key1);
                        elemValueType.setValue(value2 == null ? "" : value2.toString());
                        elemValueType.setField(parameter.getFieldCategory().getName());
                        parameterType.getParamValues().add(elemValueType);
                    }
                }
            } else {
                parameterType.setValue(value == null ? "" : value.toString()); //$NON-NLS-1$
            }
            nodeType.getElementParameter().add(parameterType);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getCodeFile".
     * 
     * @return
     */
    public IFile getCodeFile() {
        IDesignerCoreService service = DenguesCorePlugin.getDefault().getDesignerCoreService();
        IJavaETLProcessor javaProcessor = service.getJavaProcessor(getProcess(), getPath());
        return javaProcessor.getCodeFile();
    }

}
